package jp.sourceforge.akjrcp.text_douga.audio;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.math.BigDecimal;

import javax.sound.sampled.UnsupportedAudioFileException;

import jp.sourceforge.akjrcp.ffmpeg.FFMpegPCMPipeReader;
import jp.sourceforge.akjrcp.ffmpeg.ProcessListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class AudioInput implements ProcessListener{
	public static Log log=LogFactory.getLog(AudioInput.class);
private int rate=48000;
private int channel=2;

	public static final int NOT_SPECIFIED=-1;
private String ffmpegPath;
private String inputPath;
private double startTime;
private double duration=NOT_SPECIFIED;

private PipedInputStream inputStream;
private PipedOutputStream outputStream;
private boolean copying;
private boolean canceling;
private FFMpegPCMPipeReader ffreader;
public AudioInput(String ffmpegPath,String inputPath) throws IOException{
	this(ffmpegPath,inputPath,0,NOT_SPECIFIED);
}

/*
 * dont forget double value some time problem happen
 */
public AudioInput(String ffmpegPath,String inputPath,double start,double duration) throws IOException{
	this.ffmpegPath=ffmpegPath;
	this.inputPath=inputPath;
	this.startTime=start;
	this.duration=duration;
	outputStream=new PipedOutputStream();
	inputStream=new PipedInputStream(outputStream);
}

public InputStream getInputStream(){
	return inputStream;
}

public void startInput(){
	ffreader = new FFMpegPCMPipeReader(ffmpegPath,inputPath,rate,channel);
	Thread t=new Thread(ffreader);
	ffreader.setProcessListener(this);
	t.start();
	copying=true;
}

public void finished() {
	log.info("finish loading");
}

public void started() {
	try {
		BufferedInputStream binput = new BufferedInputStream(ffreader.getPCMPipeReader().getInputStream());
		long skipbyte=0;
		if(startTime!=0){
			skipbyte=new BigDecimal(""+startTime).multiply(new BigDecimal(rate*(2*channel))).longValue();//2=16bit;
		}
		log.info("should skipbyte:"+skipbyte+" "+startTime+"s");
		long mustread=0;
		if(duration!=NOT_SPECIFIED){
			BigDecimal dB = new BigDecimal(""+duration);
			mustread=dB.multiply(new BigDecimal(rate)).longValue();
			//System.out.println("tmp:"+mustread);//2 means 16bit
			mustread*=(2*channel);
			}
		//System.out.println("duration:="+duration+" rate="+rate+" channel="+channel);
		log.info("mustread:"+mustread);
		//skip input
		long skipped=0;
		byte bts2[]=new byte[1024];
		while(skipped<skipbyte){
			int r;
			if(skipped+bts2.length<skipbyte){
				r=bts2.length;
			}else{
				r=(int) (skipbyte-skipped);
			}
			int readed=binput.read(bts2,0,r);
			skipped+=readed;//take care
			if(readed==-1){//enough
				break;
			}
		}
		if(skipped>0){
			log.info("skipped:"+skipped);
		}
		
		byte bytes[]=new byte[1024];
		long readed=0;
		int read=0;
		while(read!=-1){
			if(canceling){
				break;
			}
			read = binput.read(bytes, 0, bytes.length);
			
			if(read!=-1){
				
				if(duration!=NOT_SPECIFIED){
					if(readed+read<mustread){
						outputStream.write(bytes,0,read);
					}else{
						int canwrite=(int)(mustread-readed);
						outputStream.write(bytes,0,canwrite);
						readed+=canwrite;
						log.info("over duration:");
						break;
					}
				}else{
					//just write
					outputStream.write(bytes,0,read);
				}
				readed+=read;
			}
		}
		log.info("audio readed:"+readed+" "+(readed/2/channel/rate)+"s");
		
		if(!canceling){
		if(duration!=NOT_SPECIFIED){
			//fill space 
			byte bts[]=new byte[1024];
			long writed=readed;
			while(writed<mustread){
				int w;
				if(writed+bts.length<mustread){
					w=bts.length;
				}else{
					w=(int)(mustread-writed);
				}
				outputStream.write(bts,0,w);
				writed+=w;
			}
			log.info("fill 0 data:"+(writed-readed)+" "+((writed-readed)/2/channel/rate)+"s");
		}
		}
		//pipe output close
		outputStream.flush();
		outputStream.close();
		
		
		try {
			//i don't know reason why
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		ffreader.getProcess().destroy();//good bye;
	} catch (UnsupportedAudioFileException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}finally{
		copying=false;//done
	}
}

public boolean isCanceling() {
	return canceling;
}

public void setCanceling(boolean canceling) {
	this.canceling = canceling;
}

public int getChannel() {
	return channel;
}

public void setChannel(int channel) {
	this.channel = channel;
}

public boolean isCopying() {
	return copying;
}

public void setCopying(boolean copying) {
	this.copying = copying;
}

public double getDuration() {
	return duration;
}

public void setDuration(double duration) {
	this.duration = duration;
}

public String getFfmpegPath() {
	return ffmpegPath;
}

public void setFfmpegPath(String ffmpegPath) {
	this.ffmpegPath = ffmpegPath;
}

public FFMpegPCMPipeReader getFfreader() {
	return ffreader;
}

public void setFfreader(FFMpegPCMPipeReader ffreader) {
	this.ffreader = ffreader;
}

public String getInputPath() {
	return inputPath;
}

public void setInputPath(String inputPath) {
	this.inputPath = inputPath;
}

public PipedOutputStream getOutputStream() {
	return outputStream;
}

public void setOutputStream(PipedOutputStream outputStream) {
	this.outputStream = outputStream;
}

public int getRate() {
	return rate;
}

public void setRate(int rate) {
	this.rate = rate;
}

public double getStartTime() {
	return startTime;
}

public void setStartTime(double startTime) {
	this.startTime = startTime;
}

public void setInputStream(PipedInputStream inputStream) {
	this.inputStream = inputStream;
}



}
